package com.it.controller;

import com.it.entity.User;
import com.it.service.HobbyService;
import com.it.service.LogService;
import com.it.service.UserService;
import com.it.util.*;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.validation.Valid;
import java.util.concurrent.TimeUnit;

/**
 * 描述：〈用户登入登出接口/控制器〉
 */
@Controller
public class LoginController {
    @Autowired
    private HobbyService hobbyService;
    @Autowired
    private UserService userService;
    @Autowired
    private ItdragonUtils itdragonUtils;
    @Autowired
    private LogService logService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    private static final transient Logger log = LoggerFactory.getLogger(LoginController.class);

    /**
     * 通过验证码登陆（若输入的手机号未在系统注册过就直接注册成新号，）
     */
    @ResponseBody
    @GetMapping("/logByVC")  //做测试，请求方式暂时设置为Get
    public ModelAndView loginByVerificationCode(@Valid User user, String code) {
        ModelAndView mv = new ModelAndView();
        mv.setViewName("默认的通过验证码登陆的界面");
        log.info("^^^^^^^^^^^^^^^^^^^^  用户输入的手机号: " + user.getPhoneNum() + "输入的验证码: " + code);
        try {
            Subject currentUser = getSubject();
            //判断当前系统环境是否有登录过的用户信息
            if (!currentUser.isAuthenticated()) {
                // 从Redis中获取缓存验证码
                Object codeInRedis = redisTemplate.opsForValue().get(user.getPhoneNum());

                //进行验证码的比对
                if (codeInRedis != null && codeInRedis.equals(code)) {
                    //如果能够比对成功且查询得到记录，说明登录成功
                    User userByUserPhoneNum = userService.getUserByUserPhoneNum(user.getPhoneNum());
                    if (userByUserPhoneNum != null) {
                        //不加盐
                        user.setPlainPassword(userByUserPhoneNum.getPassword());
                        log.info("^^^^^^^^^^^^^^^^^^^^  执行登录操作");
                        UsernamePasswordToken token = new UsernamePasswordToken(userByUserPhoneNum.getPhoneNum(), userByUserPhoneNum.getPassword());
                        // 执行登录
                        currentUser.login(token);
                        log.info("^^^^^^^^^^^^^^^^^^^^  登录成功");
                        //日志记录
                        //将登陆信息存储到session中
                        User loginUserInfo = new User();
                        //获取当前时间
                        String loginTime = DateUtil.getCurrentTime("yyyy-MM-dd HH:mm:ss");
                        log.info("^^^^^^^^^^^^^^^^^^^^ 登陆时间为" + loginTime);
                        loginUserInfo.setUserName(userService.getUserByUserPhoneNum(userByUserPhoneNum.getPhoneNum()).getUserName());
                        loginUserInfo.setPlainPassword(userByUserPhoneNum.getPlainPassword());
                        itdragonUtils.getShiroSession().setAttribute("loginUserInfo", loginUserInfo);
                        itdragonUtils.getShiroSession().setAttribute("userInfo", userByUserPhoneNum);
                        logService.insert("通过手机号+验证码登陆");
                        updateResidueDegreeAndDate(user, loginTime);
                        mv.addObject("ResultResponse", Result.resuleSuccess("登陆成功"));
                        //要设置成功跳转的视图
                        mv.setViewName("Ok");
                        return mv;
                    } else if (userByUserPhoneNum == null) {
                        mv.addObject("ResultResponse", Result.resuleError("登陆失败，该账号未注册过！"));
                    }
                }
                mv.addObject("ResultResponse", Result.resuleError("登陆失败，验证码不正确"));
                mv.setViewName("login");
                return mv;

            } else {
                mv.addObject("ResultResponse", Result.resuleError("已存在登录用户信息,请注销当前登录用户的信息再进行登录操作!"));
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return mv.addObject("ResultResponse", Result.resuleError("系统维护，暂时无法登陆"));
        }
    }


    /**
     * 用户通过手机号、密码登录操作
     *
     * @param phoneNum
     * @return
     */
    @ResponseBody
    @PostMapping("login.do")
    public ResultResponse login(String phoneNum, String password) {
        log.info("^^^^^^^^^^^^^^^^^^^^  登录信息:用户手机号: " + phoneNum + "密码: " + password);
        try {
            Subject currentUser = getSubject();
            //判断当前系统环境是否有登录过的用户信息
            if (!currentUser.isAuthenticated()) {
                //根据前台页面输入的用户手机号码查询用户信息
                User user = userService.getUserByUserPhoneNum(phoneNum);
                if (user == null) {
                    return Result.resuleError("用户不存在");
                } else {
                    //先不加盐
                    user.setPlainPassword(password);

                    log.info("^^^^^^^^^^^^^^^^^^^^  执行登录操作");
                    UsernamePasswordToken token = new UsernamePasswordToken(user.getPhoneNum(), password);
                    try {
                        // 执行登录
                        currentUser.login(token);
                        log.info("^^^^^^^^^^^^^^^^^^^^  登录成功");
                        //日志记录
                        //将登陆信息存储到session中
                        User loginUserInfo = new User();
                        //获取当前时间
                        String loginTime = DateUtil.getCurrentTime("yyyy-MM-dd HH:mm:ss");
                        log.info("^^^^^^^^^^^^^^^^^^^^ 登陆时间为" + loginTime);
                        loginUserInfo.setUserName(userService.getUserByUserPhoneNum(phoneNum).getUserName());
                        loginUserInfo.setPlainPassword(password);
                        itdragonUtils.getShiroSession().setAttribute("loginUserInfo", loginUserInfo);
                        itdragonUtils.getShiroSession().setAttribute("userInfo", user);
                        logService.insert("通过手机号+密码登录操作");
                        updateResidueDegreeAndDate(user, loginTime);
                        return Result.resuleSuccess();
                    } catch (AuthenticationException ae) {
                        log.info("^^^^^^^^^^^^^^^^^^^^  登录失败,账号密码不匹配: " + ae.getMessage());
                        return Result.resuleError("账号密码不匹配");
                    }
                }
            } else {
                //有登录过的用户信息返回给前台提示
                return Result.resuleError("已存在登录用户信息,请注销当前登录用户的信息再进行登录操作!");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Result.resuleError("系统维护，暂时无法登陆");
        }
    }

    //为普通用户提供的注册接口
    @ResponseBody
    @PostMapping("/register")
    public ResultResponse register(@Valid User user, String passwordVerify, String code) {
        if (isNotExist(user)) {
            // 从Redis中获取缓存验证码
            Object codeInRedis = redisTemplate.opsForValue().get(user.getPhoneNum());
            //进行验证码的比对
            if (codeInRedis != null && codeInRedis.equals(code)) {
                if (user.getPassword().equals(passwordVerify)) {
                    boolean result = userService.insert(user);
                    if (!result) {
                        return Result.resuleError("注册失败");
                    }
                    return Result.resuleSuccess("注册成功，请前往登陆");
                }
                return Result.resuleError("两次密码输入不一致，请重试！");
            } else if (codeInRedis != null && !(codeInRedis.equals(code))) {
                return Result.resuleError("验证码输入错误！");
            } else if (codeInRedis == null) {
                return Result.resuleError("验证码已过期！");
            }
        } else {
            return Result.resuleError("该手机号已经被注册使用了");
        }
        return Result.resuleError("系统繁忙，请稍后再试");
    }


    /**
     * 发送手机验证码
     */
    @ResponseBody
    @PostMapping("/sendMsg")//status为1时表示为登陆时调用发送验证码，为0时表示注册新用户时调用发送验证码
    public ResultResponse sendMsg(@Valid User user, String status) {
        Subject currentUser = getSubject();
        //判断当前系统环境是否有登录过的用户信息
        if (!currentUser.isAuthenticated()) {
            if (status.equals("0")) {
                if (isNotExist(user)) {
                    return SendVerificationCode(user);
                } else {
                    return Result.resuleError("该手机号码已经被使用过了！");
                }
            } else if (status.equals("1")) {
                if (isNotExist(user)) {
                    return Result.resuleError("该账号未注册过！");
                } else {
                    return SendVerificationCode(user);
                }
            } else {
                return Result.resuleError("系统错误，无法发送验证码");
            }
        }
        return Result.resuleError("已有登陆用户，无法发送验证码");
    }

    private Subject getSubject() {
        Subject currentUser = SecurityUtils.getSubject();
        log.info("^^^^^^^^^^^^^^^^^^^^  是否已通过认证:" + currentUser.isAuthenticated());
        return currentUser;
    }

    //测试系统中是否有此手机号码注册过的用户
    private boolean isNotExist(User user) {
        return userService.getUserByUserPhoneNum(user.getPhoneNum()) == null;
    }

    private ResultResponse SendVerificationCode(User user) {
        // 获取手机号码
        String phone = user.getPhoneNum();

        if (StringUtils.isNotEmpty(phone)) {
            //生成验证码
            String code = ValidateCodeUtils.generateValidateCode(4).toString();
            //要发送的内容
            String context = "";
            log.info("code={}", code);

            // 调用短信服务
            userService.sendMsg();

            // 验证码缓存到Redis中，并且设置验证码的有效时间为 5分钟，方便测试
            redisTemplate.opsForValue().set(phone, code, 5, TimeUnit.MINUTES);

            return Result.resuleSuccess("验证码发送成功，请及时查看!");
        }
        return Result.resuleError("验证码发送失败，请输入手机号码!");
    }

    //更新每日抽奖次数和最后一次登陆时间
    private void updateResidueDegreeAndDate(User userByUserPhoneNum, String loginTime) {
        if (userByUserPhoneNum.getUpdatedDate() != null && DateUtil.compare(userByUserPhoneNum.getUpdatedDate(), DateUtil.getCurrentTime("yyyy-MM-dd") + " 00:00:00")) {
            double floor = Math.floor(hobbyService.selectCountForUserHobbies(userByUserPhoneNum) / 2);
            userByUserPhoneNum.setResidueDegree((int) floor > 20 ? 20 : (int) floor);
            if (userService.updateByPrimaryKey(userByUserPhoneNum)) {
                log.info("^^^^^^^^^^^^^^^^^^^^ 今日第一次登陆重置抽奖次数成功");
            } else {
                log.info("^^^^^^^^^^^^^^^^^^^^ 今日第一次登陆重置抽奖次数失败!!");
            }
        } else {
            log.info("^^^^^^^^^^^^^^^^^^^^ 今日无需重置抽奖次数！");
        }
        //修改登陆时间
        userService.updateLoginTime(userByUserPhoneNum, loginTime);
    }

    /**
     * 登出
     */

    @GetMapping("logout.do")
    public String logout() {
        try {
            //退出
            SecurityUtils.getSubject().logout();
            log.info("^^^^^^^^^^^^^^^^^^^^登出成功");
        } catch (Exception e) {
            System.err.println(e.getMessage());
        } finally {
            return "redirect:/loginPaga";
        }
    }
    @GetMapping("/loginPaga")
    public String toLoginPage() {
        return "login";
    }
}